package org.xx.armory.db;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xx.armory.commons.BuilderUtils;
import org.xx.armory.config.ConfigurationManager;
import org.xx.armory.config.NamedPropertiesSection;

import javax.sql.DataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static org.xx.armory.commons.Validators.notBlank;

/**
 * 保存所有已配置数据源的工具类。
 * <p>实现按需加载。</p>
 */
public final class DataSourceStorage {
    private static final Map<String, DataSource> DATA_SOURCE_MAP = new ConcurrentHashMap<>();

    /**
     * 禁止实例化工具类。
     */
    private DataSourceStorage() {
    }

    /**
     * 获取日志对象。
     *
     * @return 日志对象。
     */
    private static Logger getLogger() {
        return LoggerFactory.getLogger(DataSourceStorage.class);
    }

    /**
     * 获取指定名字的数据源。
     *
     * @param name
     *         数据源的名字，自动去掉首尾空格。
     * @return 已创建的数据源。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符。
     * @throws IllegalStateException
     *         如果从配置中找不到指定名字的数据源。
     */
    public static DataSource getDataSource(
            String name
    ) {
        name = notBlank(name, "name").trim();

        return DATA_SOURCE_MAP.computeIfAbsent(name, DataSourceStorage::createDataSource);
    }

    /**
     * 根据名字创建数据源。
     *
     * @param name
     *         数据源的名字。
     * @return 已创建的数据源。
     * @throws IllegalStateException
     *         如果从配置中找不到指定名字的数据源。
     */
    private static DataSource createDataSource(
            String name
    ) {
        // 根据配置创建数据源。
        final NamedPropertiesSection dataSourceSection = ConfigurationManager.getConfiguration().getData().getDataSource(name);
        if (dataSourceSection == null) {
            throw new IllegalStateException("cannot find data source: " + name);
        }

        getLogger().trace("find data source: {}", name);

        final DataSource result = (DataSource) BuilderUtils.build(dataSourceSection.getClassName(), dataSourceSection.getFactoryName(), dataSourceSection.properties());

        getLogger().trace("data source created: {}", result);

        return result;
    }
}
